<!-- Created by henian.xu on 2017/6/6. -->
<template>
    <el-table
        class="tree-grid"
        v-bind="$attrs"
        :data="this.tableData"
    >
        <el-table-column
            class-name="column-expand"
            v-if="!!this.expandProp"
            :prop="this.expandProp.prop"
            :label="this.expandProp.label"
            :width="this.expandProp.width"
            :min-width="this.expandProp.minWidth"
        >
            <template slot-scope="scope">
                <div
                    :class="['indent-space',{'leaf':scope.row[prop.isLeaf]}]"
                    :style="{
                        'padding-left':(14 * scope.row[prop.level]) + 'px'
                    }"
                    @click="onRow(scope)"
                >
                    <i
                        v-if="!scope.row[prop.isLeaf]"
                        :class="{
                            'el-icon-caret-right':!scope.row[prop.expand],
                            'el-icon-caret-bottom':scope.row[prop.expand]
                        }"
                    />
                    <i
                        v-else
                        class="el-icon-caret-right"
                        style="opacity: 0"
                    />
                    <div class="node-label">{{ scope.row[expandProp.prop] }}</div>
                </div>
            </template>
        </el-table-column>

        <slot/>
    </el-table>
</template>

<script>
export default {
    name: 'TreeTable',
    data() {
        return {
            // tableData: [],
            rootNode: [],
        };
    },
    props: {
        data: {
            type: Array,
            default() {
                return [];
            },
        },
        // 展开节点属性
        expandProps: {
            type: Object,
            default() {
                return {};
            },
        },
        props: {
            type: Object,
            default() {
                return {
                    children: 'children',
                    expand: 'expand',
                    level: 'lv',
                    isLeaf: 'isLeaf',
                };
            },
        },
        rootLevel: {
            type: Number,
            default: 1,
        },
        lazyLoad: {
            type: Function,
            default: null,
        },
        initNotLoad: {
            type: Boolean,
            default: false,
        },
    },
    computed: {
        expandProp() {
            const { expandProps } = this;
            return {
                prop: '',
                label: '',
                width: expandProps.minWidth ? null : 48,
                minWidth: 48,
                ...expandProps,
            };
        },
        prop() {
            const { props } = this;
            return {
                children: 'children',
                expand: 'expand',
                level: 'lv',
                isLeaf: 'isLeaf',
                ...props,
            };
        },
        isLazy() {
            return typeof this.lazyLoad === 'function';
        },
        tableData: {
            get() {
                const { rootNode } = this;
                return this.buildTableData(rootNode);
            },
        },
    },
    methods: {
        buildTableData(list, parent, res = []) {
            parent = parent || {
                isRoot: true,
                children: this.rootNode,
            };
            const { prop } = this;
            const { children: childrenKey, expand: expandKey, level: levelKey, isLeaf: isLeafKey } = prop;
            list.forEach((item, index) => {
                this.$set(item, '_index', index);
                this.$set(item, '_parent', parent);
                this.$set(item, expandKey, !!item[expandKey]);
                this.$set(item, isLeafKey, item[isLeafKey] === null ? true : item[isLeafKey]);
                this.$set(item, childrenKey, item[childrenKey] || null);
                item[levelKey] = item[levelKey] || this.rootLevel;
                this.$set(item, levelKey, item[levelKey] || this.rootLevel);
                res.push(item);
                if (item[childrenKey] && item[expandKey]) {
                    this.buildTableData(item[childrenKey], item, res);
                }
            });
            return res;
        },
        /**
         * [懒加载]加载节点数据
         * @param row 为假侧更新根节点
         */
        loadNode(row) {
            const { lazyLoad, isLazy, prop } = this;
            if (!isLazy) return;
            return lazyLoad({ row }).then(data => {
                if (row) {
                    row[prop.children] = data;
                    // 当然新增子节点时 isLeaf 应该轩为 false
                    row[prop.isLeaf] = false;
                } else {
                    this.rootNode = data;
                }
                return Promise.resolve(data);
            });
        },
        // 行被点击
        onRow(scope) {
            const { prop } = this;
            const { row } = scope;
            const isLeaf = row[prop.isLeaf];
            const isExpand = row[prop.expand];
            if (isLeaf) return; // 如果是叶节点立即返回
            if (isExpand) {
                // collapseNode
                row[prop.expand] = false;
            } else {
                // expandNode
                row[prop.expand] = true;
                if (!row[prop.children]) this.loadNode(row);
            }
        },
        removeNode(row) {
            const { prop } = this;
            const { _parent: parent, _index: index } = row;
            parent[prop.children].splice(index, 1);
            if (parent[prop.children].length === 0) {
                parent[prop.children] = null;
                parent[prop.expand] = false;
                parent[prop.isLeaf] = true;
            }
        },
    },
    mounted() {
        this.rootNode = this.data;
        !this.initNotLoad && this.loadNode();
    },
};
</script>

<style lang="scss" scoped>
.tree-grid {
    td.column-expand {
        > .cell {
            padding-left: 5px;
            .indent-space {
                @include clearfix;
                &:not(.leaf) {
                    cursor: pointer;
                }
                > [class^='el-icon-'] {
                    float: left;
                    color: #97a8be;
                    margin: 5px 5px 5px 0;
                }
                > .node-label {
                    overflow: hidden;
                }
            }
        }
    }
}
</style>
